<!doctype html>
<!--
@license
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<html>
<head>
  <meta charset="utf-8">
  <script>
    ShadyDOM = {force: true, noPatch: true};
  </script>
  <script src="../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js"></script>
  <script src="wct-browser-config.js"></script>
  <script src="../../node_modules/wct-browser-legacy/browser.js"></script>
  <script type="module" src="../../polymer-legacy.js"></script>
</head>
<body>

  <dom-module id="x-slot">
    <template>
      <div id="container"><slot id="slot"></slot></div>
    </template>
    <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
  is: 'x-slot'
});
</script>
  </dom-module>

  <dom-module id="x-container-slot">
    <template>
      <x-slot id="container"><div id="first">first</div><slot id="slot"></slot><div id="last">last</div></x-slot>
    </template>
    <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
  is: 'x-container-slot'
});
</script>
  </dom-module>

  <dom-module id="x-event-scoped">
    <template>
      <div id="container">
        <div id="scoped"></div>
      </div>
    </template>
    <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
  is: 'x-event-scoped',
  fireComposed: function() {
    return this.fire('composed', null, {node: this.$.scoped});
  }
});
</script>
  </dom-module>

  <dom-module id="x-focusable-in-shadow">
    <template>
      <input id="focusable"></input>
    </template>
    <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
  is: 'x-focusable-in-shadow'
});
</script>
  </dom-module>

<dom-module id="x-class-bindings">
<template>
  <style>
    .a {
      border: 2px solid orange;
    }

    .aa {
      border: 12px solid red;
    }

    .b {
      padding: 4px;
    }
  </style>
  <div>
    <div id="class" class$="[[clazz]] b">class</div>
    <div id="className" class-name="[[clazz]] b">class</div>
  </div>
</template>
<script type="module">
  import { Polymer } from '../../polymer-legacy.js';
  Polymer({
    properties: {
      clazz: {type: String}
    },
    is: 'x-class-bindings'
  });
</script>
</dom-module>

   <test-fixture id="scoped">
    <template>
      <x-event-scoped></x-event-scoped>
    </template>
  </test-fixture>

  <test-fixture id="slot">
    <template>
      <x-container-slot></x-container-slot>
    </template>
  </test-fixture>

  <test-fixture id="focusableInShadow">
    <template>
      <x-focusable-in-shadow></x-focusable-in-shadow>
    </template>
  </test-fixture>

<script type="module">
import { dom } from '../../lib/legacy/polymer.dom.js';
import { useShadow, useNativeCustomElements, useNativeCSSProperties } from '../../lib/utils/settings.js';

suite('extended dom api', function() {
  test('getEffectiveChildNodes', function() {
    var el = fixture('slot');
    var div = document.createElement('div');
    dom(el).appendChild(div);
    if (window.ShadyDOM) {
      ShadyDOM.flush();
    }
    assert.deepEqual(dom(el).getEffectiveChildNodes(),
      [div]);
    assert.deepEqual(dom(el.$.container).getEffectiveChildNodes(),
      [el.$.first, div, el.$.last]);
    assert.deepEqual(dom(el.$.container.$.container).getEffectiveChildNodes(),
      [el.$.first, div, el.$.last]);
  });

  test('queryDistributedElements', function() {
    var el = fixture('slot');
    var div = document.createElement('div');
    dom(el).appendChild(div);
    if (window.ShadyDOM) {
      ShadyDOM.flush();
    }
    assert.deepEqual(dom(el).queryDistributedElements('foo'),
      []);
    assert.deepEqual(dom(el).queryDistributedElements('div'),
      [div]);
    assert.deepEqual(dom(el.$.container).queryDistributedElements('#first'),
      [el.$.first]);
    assert.deepEqual(dom(el.$.container.$.container).queryDistributedElements('#last'),
      [el.$.last]);
  });

});

suite('distribution', function() {
  test('getDistributedNodes', function() {
    var el = fixture('slot');
    var div = document.createElement('div');
    dom(el).appendChild(div);
    if (window.ShadyDOM) {
      ShadyDOM.flush();
    }
    assert.deepEqual(dom(el.$.slot).getDistributedNodes(), [div]);
    assert.deepEqual(dom(el.$.container.$.slot).getDistributedNodes(),
      [el.$.first, div, el.$.last]);
  });

  test('getDestinationInsertionPoints', function() {
    var el = fixture('slot');
    var div = document.createElement('div');
    dom(el).appendChild(div);
    if (window.ShadyDOM) {
      ShadyDOM.flush();
    }
    assert.deepEqual(dom(el.$.first).getDestinationInsertionPoints(),
      [el.$.container.$.slot]);
    assert.deepEqual(dom(div).getDestinationInsertionPoints(),
      [el.$.slot, el.$.container.$.slot]);
  });
});

suite('events', function() {

  test('localTarget, rootTarget, path', function() {
    // skip if noPatch is not available
    if (!window.ShadyDOM.wrap) {
      this.skip();
    }
    var el = fixture('scoped');
    el.addEventListener('composed', function(e) {
      assert.equal(dom(e).rootTarget, el.$.scoped);
      assert.equal(dom(e).localTarget, el);
      let nodes = [];
      let p = el.$.scoped;
      while (p) {
        nodes.push(p);
        p = dom(p).parentNode || ShadyDOM.wrap(p).host;
      }
      nodes.push(window);
      const path = dom(e).path;
      assert.deepEqual(path, nodes);
    });
    ShadyDOM.flush();
    el.fireComposed();
  });

  test('localTarget when target node and event listener node are distinct', function() {
    // skip if noPatch is not available
    if (!window.ShadyDOM.wrap) {
      this.skip();
    }
    var el = fixture('scoped');
    el.$.container.addEventListener('composed', function(e) {
      assert.equal(dom(e).rootTarget, el.$.scoped);
      assert.equal(dom(e).localTarget, el.$.scoped);
    });
    ShadyDOM.flush();
    el.fireComposed();
  });

});

suite('activeElement getter', function() {
  test('Retrieves `activeElement`', function() {
    // skip if noPatch is not available
    if (!window.ShadyDOM.wrap) {
      this.skip();
    }
    var focusableInShadow = fixture('focusableInShadow');
    ShadyDOM.wrap(focusableInShadow.$.focusable).focus();
    var rootNode = ShadyDOM.wrap(focusableInShadow).getRootNode();
    assert.equal(dom(rootNode).activeElement, focusableInShadow);
    assert.equal(dom(dom(focusableInShadow).shadowRoot).activeElement, focusableInShadow.$.focusable);
  });
});

suite('legacy api', function() {
  test('getEffectiveChildNodes', function() {
    var el = fixture('slot');
    var div = document.createElement('div');
    var t = document.createTextNode('yo');
    dom(el).appendChild(div);
    dom(el).appendChild(t);
    if (window.ShadyDOM) {
      ShadyDOM.flush();
    }
    assert.deepEqual(el.getEffectiveChildNodes(),
      [div, t]);
    assert.deepEqual(el.$.container.getEffectiveChildNodes(),
      [el.$.first, div, t, el.$.last]);
  });

  test('getEffectiveChildren', function() {
    var el = fixture('slot');
    var div = document.createElement('div');
    dom(el).appendChild(div);
    if (window.ShadyDOM) {
      ShadyDOM.flush();
    }
    assert.deepEqual(el.getEffectiveChildNodes(),
      [div]);
    assert.deepEqual(el.$.container.getEffectiveChildNodes(),
      [el.$.first, div, el.$.last]);
  });

  test('getEffectiveTextContent', function() {
    var el = fixture('slot');
    var t1 = document.createTextNode('a');
    var t2 = document.createTextNode('b');
    dom(el).appendChild(t1);
    dom(el).appendChild(t2);
    if (window.ShadyDOM) {
      ShadyDOM.flush();
    }
    assert.deepEqual(el.getEffectiveTextContent(), 'ab');
    assert.deepEqual(el.$.container.getEffectiveTextContent(), 'firstablast');
  });

  test('getContentChildNodes', function() {
    var el = fixture('slot');
    var div1 = document.createElement('div');
    var t = document.createTextNode('');
    var div2 = document.createElement('div');
    dom(el).appendChild(div1);
    dom(el).appendChild(t);
    dom(el).appendChild(div2);
    if (window.ShadyDOM) {
      ShadyDOM.flush();
    }
    assert.deepEqual(el.getContentChildNodes(),
      [div1, t, div2]);
    assert.deepEqual(el.getContentChildNodes('slot'),
      [div1, t, div2]);
  });

  test('getContentChildren', function() {
    var el = fixture('slot');
    var div1 = document.createElement('div');
    var t = document.createTextNode('');
    var div2 = document.createElement('div');
    dom(el).appendChild(div1);
    dom(el).appendChild(t);
    dom(el).appendChild(div2);
    if (window.ShadyDOM) {
      ShadyDOM.flush();
    }
    assert.deepEqual(el.getContentChildren(),
      [div1, div2]);
    assert.deepEqual(el.getContentChildren('slot'),
      [div1, div2]);
  });

  test('queryDistributedElements', function() {
    var el = fixture('slot');
    var div = document.createElement('div');
    dom(el).appendChild(div);
    if (window.ShadyDOM) {
      ShadyDOM.flush();
    }
    assert.deepEqual(el.queryDistributedElements('foo'),
      []);
    assert.deepEqual(el.queryDistributedElements('div'),
      [div]);
    assert.deepEqual(el.$.container.queryDistributedElements('#first'),
      [el.$.first]);
  });

  test('queryEffectiveChildren', function() {
    var el = fixture('slot');
    var div = document.createElement('div');
    dom(el).appendChild(div);
    if (window.ShadyDOM) {
      ShadyDOM.flush();
    }
    assert.equal(el.queryEffectiveChildren('foo'),
      null);
    assert.deepEqual(el.queryEffectiveChildren('div'),
      div);
    assert.deepEqual(el.$.container.queryEffectiveChildren('#first'),
      el.$.first);
  });

  test('queryAllEffectiveChildren', function() {
    var el = fixture('slot');
    var div1 = document.createElement('div');
    var div2 = document.createElement('div');
    dom(el).appendChild(div1);
    dom(el).appendChild(div2);
    if (window.ShadyDOM) {
      ShadyDOM.flush();
    }
    assert.deepEqual(el.queryAllEffectiveChildren('foo'),
      []);
    assert.deepEqual(el.queryAllEffectiveChildren('div'),
      [div1, div2]);
    assert.deepEqual(el.$.container.queryAllEffectiveChildren('div'),
      [el.$.first, div1, div2, el.$.last]);
  });

  test('isLightDescendant', function() {
    var el = fixture('slot');
    var div1 = document.createElement('div');
    dom(el).appendChild(div1);
    if (window.ShadyDOM) {
      ShadyDOM.flush();
    }
    assert.equal(el.isLightDescendant(div1), true);
    assert.equal(el.isLightDescendant(el.$.container), false);
  });

  test('isLocalDescendant', function() {
    var el = fixture('slot');
    var div1 = document.createElement('div');
    dom(el).appendChild(div1);
    if (window.ShadyDOM) {
      ShadyDOM.flush();
    }
    assert.equal(el.isLocalDescendant(div1), false);
    assert.equal(el.isLocalDescendant(el.$.container), true);
  });

  test('domHost', function() {
    var el = fixture('slot');
    assert.equal(el.domHost, document);
    assert.equal(el.$.container.domHost, el);
  });

  test('legacy settings', function() {
    assert.equal(useShadow, !(window.ShadyDOM));
    assert.equal(useNativeCustomElements, !(window.customElements.polyfillWrapFlushCallback));
    assert.equal(useNativeCSSProperties, Boolean(!window.ShadyCSS || window.ShadyCSS.nativeCss));
  });

});

suite('forwarded native api', function() {

  let el;

  setup(function() {
    el = document.createElement('x-container-slot');
    document.body.appendChild(el);
  });

  teardown(function() {
    document.body.removeChild(el);
  });

  test('accessors are available', function() {
    const d = dom(el);
    assert.isDefined(d.parentNode);
    assert.isDefined(d.firstChild);
    assert.isDefined(d.lastChild);
    assert.isDefined(d.nextSibling);
    assert.isDefined(d.previousSibling);
    assert.isDefined(d.firstElementChild);
    assert.isDefined(d.lastElementChild);
    assert.isDefined(d.nextElementSibling);
    assert.isDefined(d.previousElementSibling);
    assert.isDefined(d.childNodes);
    assert.isDefined(d.children);
    assert.isDefined(d.classList);
    assert.isDefined(d.textContent);
    assert.isDefined(d.innerHTML);
  });

  test('cloneNode', function() {
    const clone = dom(el).cloneNode(el);
    assert.ok(clone);
    assert.equal(clone.localName, 'x-container-slot');
  });

  test('appendChild', function() {
    const d1 = document.createElement('div');
    dom(el).appendChild(d1);
    assert.equal(dom(el).firstChild, d1);
    assert.equal(dom(d1).parentNode, el);
  });

  test('insertBefore', function() {
    const d1 = document.createElement('div');
    const d2 = document.createElement('div');
    dom(el).appendChild(d1);
    dom(el).insertBefore(d2, d1);
    assert.equal(dom(d2).nextSibling, d1);
  });

  test('removeChild', function() {
    const d1 = document.createElement('div');
    dom(el).appendChild(d1);
    dom(el).removeChild(d1);
    assert.equal(dom(d1).parentNode, null);
  });

  test('replaceChild', function() {
    const d1 = document.createElement('div');
    const d2 = document.createElement('div');
    dom(el).appendChild(d1);
    dom(el).replaceChild(d2, d1);
    assert.equal(dom(d1).parentNode, null);
    assert.equal(dom(el).firstChild, d2);
    assert.equal(dom(d2).parentNode, el);
  });

  test('replaceChild', function() {
    dom(el).setAttribute('foo', 'foo');
    assert.equal(el.getAttribute('foo'), 'foo');
  });

  test('replaceChild', function() {
    dom(el).setAttribute('foo', 'foo');
    dom(el).removeAttribute('foo');
    assert.isFalse(el.hasAttribute('foo'));
  });

  test('querySelector', function() {
    const d1 = document.createElement('div');
    dom(el).appendChild(d1);
    const query = dom(el).querySelector('div');
    assert.equal(query, d1);
  });

  test('querySelectorAll', function() {
    const d1 = document.createElement('div');
    const d2 = document.createElement('div');
    dom(el).appendChild(d1);
    dom(el).appendChild(d2);
    const query = dom(el).querySelectorAll('div');
    assert.equal(query[0], d1);
    assert.equal(query[1], d2);
    assert.equal(query.length, 2);
  });

  test('tree accessors', function() {
    const d1 = document.createElement('div');
    const d2 = document.createElement('div');
    dom(el).appendChild(d1);
    dom(el).appendChild(d2);
    const pel = dom(el);
    const pd1 = dom(d1);
    const pd2 = dom(d2);
    assert.equal(pd1.parentNode, el);
    assert.equal(pel.firstChild, d1);
    assert.equal(pel.lastChild, d2);
    assert.equal(pel.firstElementChild, d1);
    assert.equal(pel.lastElementChild, d2);
    assert.equal(pd1.nextSibling, d2);
    assert.equal(pd2.previousSibling, d1);
    assert.equal(pd1.nextElementSibling, d2);
    assert.equal(pd2.previousElementSibling, d1);
    assert.equal(pel.childNodes[0], d1);
    assert.equal(pel.childNodes[1], d2);
    assert.equal(pel.children[0], d1);
    assert.equal(pel.children[1], d2);
  });

  test('innerHTML', function() {
    dom(el).innerHTML = '<div></div>';
    assert.equal(dom(el).firstChild.localName, 'div');
  });

  test('textContent', function() {
    dom(el).innerHTML = 'hi';
    assert.equal(dom(dom(el).firstChild).textContent, 'hi');
  });

  test('classList', function() {
    dom(el).classList.add('foo');
    assert.equal(el.className, 'foo');
  });

  test('className', function() {
    dom(el).className = 'foo';
    assert.isTrue(el.classList.contains('foo'));
  });

  test('class bindings work and remained scoped', function() {
    const el = document.createElement('x-class-bindings');
    document.body.appendChild(el);
    assert.equal(getComputedStyle(el.$.class)['border-top-width'], '0px');
    assert.equal(getComputedStyle(el.$.class)['padding-top'], '4px');
    assert.isTrue(el.$.class.classList.contains('style-scope'));
    assert.equal(getComputedStyle(el.$.className)['border-top-width'], '0px');
    assert.equal(getComputedStyle(el.$.className)['padding-top'], '4px');
    assert.isTrue(el.$.className.classList.contains('style-scope'));
    el.clazz = 'a';
    assert.equal(getComputedStyle(el.$.class)['border-top-width'], '2px');
    assert.equal(getComputedStyle(el.$.class)['padding-top'], '4px');
    assert.isTrue(el.$.class.classList.contains('style-scope'));
    assert.equal(getComputedStyle(el.$.className)['border-top-width'], '2px');
    assert.equal(getComputedStyle(el.$.className)['padding-top'], '4px');
    assert.isTrue(el.$.className.classList.contains('style-scope'));
    el.clazz = 'aa';
    assert.equal(getComputedStyle(el.$.class)['border-top-width'], '12px');
    assert.equal(getComputedStyle(el.$.class)['padding-top'], '4px');
    assert.isTrue(el.$.class.classList.contains('style-scope'));
    assert.equal(getComputedStyle(el.$.className)['border-top-width'], '12px');
    assert.equal(getComputedStyle(el.$.className)['padding-top'], '4px');
    assert.isTrue(el.$.className.classList.contains('style-scope'));
    document.body.removeChild(el);
  });

});
</script>

</body>
</html>
